#ifndef APP_ALGORITHM_UTILS_INCLUDE_ALGORITHM_RANDOM_H
#define APP_ALGORITHM_UTILS_INCLUDE_ALGORITHM_RANDOM_H

// #include <format>
#include <iostream>
#include <memory>
#include <random>
#include <ranges>
#include <string>
#include <unordered_map>
#include <vector>

namespace utils {
inline constexpr size_t DEFAULT_MINIMUM_CONTAINER_SIZE = 100;
inline constexpr size_t DEFAULT_MAXIMUM_CONTAINER_SIZE = 10000;
inline constexpr int32_t DEFAULT_MINIMUM_RANDOM_NUMBER = -1000;
inline constexpr int32_t DEFAULT_MAXIMUM_RANDOM_NUMBER = 1000;
inline constexpr int32_t DEFAULT_MINIMUM_STRING_LENGTH = 1;
inline constexpr int32_t DEFAULT_MAXIMUM_STRING_LENGTH = 100;
inline constexpr int32_t DEFAULT_MINIMUM_TREE_DEPTH = 1;
inline constexpr int32_t DEFAULT_MAXIMUM_TREE_DEPTH = 5;
inline constexpr std::string_view DEFAULT_CHAR_SET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

struct Int32Config {
    int32_t minValue = DEFAULT_MINIMUM_RANDOM_NUMBER;
    int32_t maxValue = DEFAULT_MAXIMUM_RANDOM_NUMBER;
};

struct StringConfig {
    int32_t minLength = DEFAULT_MINIMUM_STRING_LENGTH;
    int32_t maxLength = DEFAULT_MAXIMUM_STRING_LENGTH;
    std::string_view charSet = DEFAULT_CHAR_SET;
};

struct TreeConfig {
    int32_t minValue = DEFAULT_MINIMUM_RANDOM_NUMBER;
    int32_t maxValue = DEFAULT_MAXIMUM_RANDOM_NUMBER;
    size_t minDepth = DEFAULT_MINIMUM_TREE_DEPTH;
    size_t maxDepth = DEFAULT_MAXIMUM_TREE_DEPTH;
};

struct ContainerConfig {
    int32_t minSize = DEFAULT_MINIMUM_CONTAINER_SIZE;
    int32_t maxSize = DEFAULT_MAXIMUM_CONTAINER_SIZE;
};

struct TreeNode {
    int32_t val;
    std::unique_ptr<TreeNode> left;
    std::unique_ptr<TreeNode> right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    explicit TreeNode(int32_t x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int32_t x, std::unique_ptr<TreeNode> leftPtr, std::unique_ptr<TreeNode> rightPtr)
        : val(x), left(std::move(leftPtr)), right(std::move(rightPtr)) {}
};

class AlgorithmRandom {
public:
    static int32_t GenerateInt32(const Int32Config &config = Int32Config{});

    static std::string GenerateString(const StringConfig &config = StringConfig{});

    static std::unique_ptr<TreeNode> GenerateBinaryTree(const TreeConfig &config = TreeConfig{});

private:
    static std::mt19937& GetRandomEngine();

    template<std::integral T>
    static T GenerateNumber(T minValue, T maxValue);

    template<std::floating_point T>
    static T GenerateNumber(T minValue, T maxValue);

    static std::unique_ptr<TreeNode> GenerateTreeRecursive(const TreeConfig &config, size_t currentDepth);
};
} // namespace utils

#endif // APP_ALGORITHM_UTILS_INCLUDE_ALGORITHM_RANDOM_H